package com.zxq.ai.aop;


import com.zxq.common.utils.JsonUtil;
import com.zxq.common.utils.exception.ErrorCode;
import com.zxq.common.utils.exception.IErrorCode;
import com.zxq.common.utils.response.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 只拦截最外层Service
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
@Aspect
@Component
@Slf4j
public class ControllerExceptionAspect {

    @Around("execution(* com.zxq.ai.controller..*.*(..))")
    public Object rpcAop(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Class<?> returnType = signature.getReturnType();
        String methodName = getMethodName(joinPoint);
        String request = null;
        Object response;
        try {
            request = JsonUtil.toJson(joinPoint.getArgs());
            log.info("{}, Request:{}", methodName, request);

            response = joinPoint.proceed();
            log.info("{}, Response:{}, Request:{}", methodName, JsonUtil.toJson(response), request);
        } catch (Exception e) {
            ErrorCode errorCode = consumerException(e);
            String errMsg = StringUtils.defaultIfEmpty(e.getMessage(), errorCode.getMessage());
            response = getFailResponse(errorCode.getCode(), errMsg, returnType);

            log.error("{}, Response:{}, Request:{}, error:", methodName, JsonUtil.toJson(response), request, e);
            // if (AlarmLevel.NO_ALARM == errorCode.getAlarmLevel()) {
            //     log.info("{}, Response:{}, Request:{}, error:{}", methodName, JsonUtil.toJson(response), request, e);
            // } else {
            //     log.error("{}, Response:{}, Request:{}, error:", methodName, JsonUtil.toJson(response), request, e);
            // }
        }
        return response;
    }

    private String getMethodName(ProceedingJoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();

        return String.format("%s.%s", className, methodName);
    }

    public Object getFailResponse(int code, String message, Class<?> returnType) throws Throwable {
        if ((BaseResponse.class).isAssignableFrom(returnType)) {
            Method setCode = Arrays.stream(returnType.getMethods())
                    .filter(method -> "setCode".equalsIgnoreCase(method.getName()))
                    .findFirst()
                    .orElse(null);

            Method setMsg = Arrays.stream(returnType.getMethods())
                    .filter(method -> "setMsg".equalsIgnoreCase(method.getName()))
                    .findFirst()
                    .orElse(null);

            if (setMsg == null) {
                setMsg = Arrays.stream(returnType.getMethods())
                        .filter(method -> "setMessage".equalsIgnoreCase(method.getName()))
                        .findFirst()
                        .orElse(null);
            }

            if (setMsg != null && setCode != null) {
                Object result = returnType.getDeclaredConstructor().newInstance();
                setCode.invoke(result, code);
                setMsg.invoke(result, message);
                return result;
            }
        }
        throw new Exception("ServiceExceptionAspect切面打标的接口必须继承BaseResponse");
    }

    public ErrorCode consumerException(Exception e) {
        if (e instanceof IErrorCode) {
            return ((IErrorCode) e).getCode();
        } else if (e instanceof IllegalArgumentException) {
            return ErrorCode.PARAM_ERROR;
        } else {
            return ErrorCode.BUSINESS_ERROR;
        }


    }

}

